import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog, messagebox
import threading
import os
import glob2 as glob
import cv2
import numpy as np
from scipy import ndimage
from PIL import Image, ImageEnhance, ImageOps  # pip install pillow
import math

folder_selected = None
my_files = None
image_files = None


# -------------------tab1---------------------------------------------
def main_quality_check(img_name):
    # im1 = cv2.imread(img_name)
    im1 = cv2.imdecode(np.fromfile(img_name, dtype=np.uint8), -1)
    # 将图像转换为灰度图
    gray_img = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY)
    # 将灰度图像转换为浮点数
    distImage = gray_img.astype(np.float64)
    # 使用Sobel算子计算边缘
    edgeSobel = cv2.Canny(gray_img, 50, 150)
    # 计算边缘的均值和标准差
    edgeMean = np.mean(edgeSobel)
    edgeStd = np.std(edgeSobel)
    # 计算局部方差
    localVariance = ndimage.variance(distImage)  # , mode='constant', cval=0.0)
    # 计算纹理的均值和标准差
    textureMean = np.mean(localVariance)
    textureStd = np.std(localVariance)
    # 计算质量分数
    ImageMean = np.mean(distImage)
    ImageStd = np.std(distImage)
    qnr = 20 * np.log10((edgeMean + textureMean + ImageMean) / (edgeStd + textureStd + ImageStd))
    print(qnr)
    return round(qnr, 1)


def background_task():
    file = open(folder_selected + os.sep + os.path.basename(folder_selected) + "quality.txt", "w", encoding="utf-8")
    i = 0
    progressbar['value'] = 0
    global my_files
    for imgFile in my_files:
        print(imgFile)
        qnr = main_quality_check(imgFile)  # folder_selected + os.sep +
        line_str = os.path.basename(imgFile) + "    " + str(qnr) + "\r\n"
        file.write(line_str)
        i = i + 1
        rate = i / len(my_files) * 100
        print(str(round(rate, 0)) + "%")
        # show_info.set(str(rate)+"%")
        progressbar['value'] = rate
    file.close()
    show_info.set("操作成功！")
    button1.config(state="normal")


def choose_dir():
    global folder_selected
    folder_selected = filedialog.askdirectory()
    print(folder_selected)
    show_info.set(folder_selected)
    global my_files
    # my_files = os.listdir(folder_selected)
    pattern = os.path.join(folder_selected, "*.JPG")
    my_files1 = glob.glob(pattern)
    pattern = os.path.join(folder_selected, "*.jpeg")
    my_files2 = glob.glob(pattern)
    my_files = my_files1 + my_files2
    if len(my_files) == 0:
        show_info.set("目录中没有照片!")
        return
    button1.config(state="disable")
    background_thread = threading.Thread(target=background_task)
    background_thread.daemon = True
    background_thread.start()


# -------------------tab2---------------------------------------------
def do_bright(img_todo_dict, bright_ok_mean):
    i = 0
    for key, value in img_todo_dict.items():
        brightness_rate = bright_ok_mean / value
        image = Image.open(key)
        image_info = ImageOps.exif_transpose(image)
        if image.size != image_info.size:
            image = image.rotate(270, expand=1)
        enhancer = ImageEnhance.Brightness(image)
        bright_image = enhancer.enhance(brightness_rate)
        img_dir = os.path.dirname(key)
        img_name = os.path.basename(key)
        img_dir_new = os.path.join(img_dir, 'brightness_out')
        if not os.path.exists(img_dir_new):
            os.mkdir(img_dir_new)
        img_path = os.path.join(img_dir_new, img_name)
        bright_image.save(img_path)
        i = i + 1
        rate = i / len(img_todo_dict) * 100 / 2
        progressbar['value'] = rate + 50
    labelInfo.config(text="操作成功！")
    button2.config(state="normal")


def get_photo_brightness(image_path):
    # 加载图像
    image = Image.open(image_path)
    # 转换为灰度图像
    gray_image = image.convert("L")
    # 计算图像亮度
    brightness = sum(gray_image.getdata()) / len(gray_image.getdata())
    # 输出结果
    print("图像亮度：", brightness)
    return brightness;


def get_camera_parameters(image_path):
    try:
        # 打开图像文件
        with Image.open(image_path) as img:
            # 获取 Exif 数据
            exif_data = img._getexif()

            # 如果存在 Exif 数据
            if exif_data is not None:
                # 获取相机制造商和型号
                make = exif_data.get(271)
                model = exif_data.get(272)

                # 获取曝光时间
                exposure_time = exif_data.get(33434)

                # 获取光圈值
                aperture_value = exif_data.get(33437)

                # 获取焦距
                focal_length = exif_data.get(37386)

                # 获取亮度值
                brightness_value = exif_data.get(37379)  # 0x9203

                # 返回相机参数
                return {
                    "make": make,
                    "model": model,
                    "exposure_time": exposure_time,
                    "aperture_value": aperture_value,
                    "focal_length": focal_length,
                    "brightness_value": brightness_value
                }

            else:
                return None

    except (IOError, ValueError):
        return None


def list_image_files(directory):
    image_extensions = ["*.jpg", "*.jpeg", "*.png", "*.gif"]
    image_files = []
    for extension in image_extensions:
        pattern = os.path.join(directory, extension)
        image_files.extend(glob.glob(pattern))
    return image_files


def background_task2():
    bright_arr = []
    bright_ok_mean = 0.0
    img_todo_dict = {}
    i = 0
    progressbar['value'] = 0
    global image_files
    for image_file in image_files:
        print(image_file)
        photo_data = get_camera_parameters(image_file)
        print(photo_data)
        if photo_data is None:
            continue
        brightness = get_photo_brightness(image_file)
        if photo_data["brightness_value"] is None \
                or photo_data["brightness_value"] < 0:
            continue
        else:
            bright_arr.append(brightness)
            img_todo_dict[image_file] = brightness
        i = i + 1
        rate = i / len(image_files) * 100 / 2
        progressbar['value'] = rate
    bright_ok_mean = sum(bright_arr) / len(bright_arr)
    print(bright_ok_mean)
    do_bright(img_todo_dict, bright_ok_mean)


def choose_directory():
    directory = filedialog.askdirectory()
    labelInfo.config(text="选择的目录：" + directory)
    global image_files
    image_files = list_image_files(directory)
    if len(image_files) == 0:
        show_info.set("目录中没有照片!")
        return
    button2.config(state="disable")
    background_thread = threading.Thread(target=background_task2)
    background_thread.daemon = True
    background_thread.start()


# -------------------tab3---------------------------------------------
arr = []
img = None


def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        global arr
        arr.append([x, y])
        global img
        cv2.circle(img, (x, y), 8, (255, 0, 255), thickness=3)
        cv2.imshow("rotate_set", img)
        if len(arr) == 2:
            cv2.line(img, (arr[0][0], arr[0][1]), (arr[1][0], arr[1][1]), (0, 255, 0), thickness=3)
            cv2.imshow("rotate_set", img)


def doCV2(src_FILE):
    global img
    img = cv2.imread(src_FILE)
    cv2.namedWindow("rotate_set", cv2.WINDOW_FREERATIO)
    cv2.setMouseCallback("rotate_set", on_EVENT_LBUTTONDOWN)
    cv2.imshow("rotate_set", img)
    global arr
    if len(arr) == 2 or cv2.waitKey(0) == 27:
        cv2.destroyAllWindows()
        if len(arr) != 2:
            return
        # 获取旋转角度
        angle_rad = math.atan2(arr[1][1] - arr[0][1], arr[1][0] - arr[0][0])
        angle_deg = math.degrees(angle_rad)
        print(f"Angle in degrees: {angle_deg}")
        arr = []
        angle_deg_new = angle_deg
        if angle_deg_new > 0:
            angle_deg_new = format(360-angle_deg, '.2f')
        else:
            angle_deg_new = format(angle_deg*(-1), '.2f')
        is_do_rotate = messagebox.askyesno("是否旋转", f"角度为{angle_deg}°\n,是否执行旋转到{angle_deg_new}°?")
        if is_do_rotate:
            image = Image.open(src_FILE)
            # 向右旋转angle_deg度,expand参数让图片尺寸适应新的形状
            rotated_image = image.rotate(angle_deg, expand=True)
            # 保存旋转后的图片,可以给它一个新的文件名
            img_dir_new = os.path.join(os.path.dirname(src_FILE), 'rotate')
            if not os.path.exists(img_dir_new):
                os.mkdir(img_dir_new)
            file_name = os.path.basename(src_FILE)
            file_name_new = os.path.splitext(file_name)[0] + "_" + format(angle_deg, '.0f') + os.path.splitext(file_name)[1]
            save_path = os.path.join(img_dir_new, file_name_new)
            rotated_image.save(save_path)
            img_new = cv2.imread(save_path)
            cv2.namedWindow(file_name_new, cv2.WINDOW_FREERATIO)
            cv2.imshow(file_name_new, img_new)
            cv2.waitKey(0)
            cv2.destroyAllWindows()



def choose_image():
    src_FILE = filedialog.askopenfilename(initialdir="images/", title="选择图片",
                                          filetypes=(("JPEG files", "*.jpg"), ("PNG files", "*.png")))
    print(src_FILE)
    doCV2(src_FILE)


root = tk.Tk()
root.geometry("500x500")
root.title("照片检测处理工具v1.0")
tab_container = ttk.Notebook(root)
tab_container.pack(fill='both', expand=1)
# tab1
frame1 = tk.Frame(tab_container)
tab_container.add(frame1, text="照片质量检测工具")
# 选择按钮
button1 = tk.Button(frame1, text="选择照片目录", command=choose_dir)
button1.pack(side="top", pady=50)
# 提示信息
show_info = tk.StringVar()
panel = tk.Label(frame1, text='图片目录:', textvariable=show_info)
panel.pack(side="top", padx="50", pady="50")
# tab2
frame2 = tk.Frame(tab_container)
tab_container.add(frame2, text="照片亮度处理工具")
# 选择按钮
button2 = tk.Button(frame2, text="选择目录", command=choose_directory)
button2.pack(pady=50)
# 提示信息
labelInfo = tk.Label(frame2, text="选择的目录：")
labelInfo.pack(pady=50)
# tab3
frame3 = tk.Frame(tab_container)
tab_container.add(frame3, text="照片旋转工具")
button = tk.Button(frame3, text="选择图片", command=choose_image)
button.pack(side="top", pady=50)
# 底部进度条
progressbar = ttk.Progressbar(root, orient='horizontal', length=300)
progressbar.pack(side="bottom", pady=5, expand="yes")
root.mainloop()
